package xxl.robotlegs.framework.impl 
{
	import xxl.robotlegs.framework.api.IContext;
	import xxl.robotlegs.framework.api.IContextLifecycleSignal;
	import xxl.robotlegs.framework.api.IInjector;
	import xxl.robotlegs.framework.api.ILogger;
	import xxl.robotlegs.framework.api.ILogTarget;
	import xxl.robotlegs.framework.api.IMatcher;
	import xxl.robotlegs.framework.impl.lifecycle.Lifecycle;
	import xxl.robotlegs.framework.impl.lifecycle.LifecycleSignal;
	import xxl.robotlegs.framework.impl.log.LogManager;
	import xxl.robotlegs.utils.UID;
	import xxl.signals.api.events.IEvent;
	/**
	 * ...
	 * @author XXL
	 */
	public class Context implements IContext
	{
		private const _uid:String = UID.Create(Context);
		private const _injector:IInjector = new RobotlegsInjector();
		private const _logManager:LogManager = new LogManager();
		private const _children:Array = [];
		private const _contextLifecycleSignal:LifecycleSignal = new LifecycleSignal(this);
		private var _logger:ILogger;
		private var _pin:Pin;
		private var _configManager:ConfigManager;
		private var _extensionInstaller:ExtensionInstaller;
		private var _lifecycle:Lifecycle;
		
		public function Context() 
		{
			setup();
		}
		
		public function toString():String
		{
			return _uid;
		}
		
		private function setup():void
		{
			_injector.map(IInjector).toValue(_injector);
			_injector.map(IContext).toValue(this);
			_logger = _logManager.getLogger(this);
			_pin = new Pin();
			_lifecycle = new Lifecycle(this, _contextLifecycleSignal);
			_configManager = new ConfigManager(this);
			_extensionInstaller = new ExtensionInstaller(this);
			beforeInitializing(beforeInitializingCallback);
			afterInitializing(afterInitializingCallback);
			beforeDestroying(beforeDestroyingCallback);
			afterDestroying(afterDestroyingCallback);
		}
		
		private function beforeInitializingCallback():void
		{
			_logger.info("初始化中...");
		}
		
		private function afterInitializingCallback():void
		{
			_logger.info("初始化成功");
		}

		private function beforeDestroyingCallback():void
		{
			_logger.info("销毁中...");
		}
		
		private function afterDestroyingCallback():void
		{
			_pin.releaseAll();
			_injector.teardown();
			removeChildren();
			_logger.info("销毁成功");
		}
		
		private function removeChildren():void
		{
			for (var i:int = _children.length; i--; )
			{
				removeChild(_children[i]);
			}
			_children.length = 0;
		}
		
		private function onChildDestroy(event:IEvent):void
		{
			removeChild(event.target as IContext);
		}
		
		/* INTERFACE xxl.robotlegs.core.IContext */
		
		public function get injector():IInjector 
		{
			return _injector;
		}
		
		public function get logLevel():uint 
		{
			return _logManager.logLevel;
		}
		
		public function set logLevel(value:uint):void 
		{
			_logManager.logLevel = value;
		}
		
		public function install(...extensions):IContext 
		{
			const len:int = extensions.length;
			for (var i:int = 0; i < len; i++) 
			{
				_extensionInstaller.install(extensions[i]);
			}
			return this;
		}
		
		public function configure(...configs):IContext 
		{
			const len:int = configs.length;
			for (var i:int = 0; i < len; i++) 
			{
				_configManager.addConfig(configs[i]);
			}
			return this;
		}
		
		public function addChild(child:IContext):IContext 
		{
			if (_children.indexOf(child) == -1)
			{
				_logger.info("添加了一个子context {0}", [child]);
				if (!child.uninitialized)
				{
					_logger.warn("子context {0} 必须是未初始化的", [child]);
				}
				if (child.injector.parent)
				{
					_logger.warn("子context {0} 的Injector不能有父Injector", [child]);
				}
				_children.push(child);
				child.injector.parent = injector;
				child.contextLifecycleSignal.addOnceToMap(LifecycleSignal.POST_DESTROY, onChildDestroy);
			}
			return this;
		}
		
		public function removeChild(child:IContext):IContext 
		{
			const childIndex:int = _children.indexOf(child);
			if (childIndex >= 0)
			{
				_logger.info("删除了一个子context {0}", [child]);
				_children.splice(childIndex, 1);
				child.injector.parent = null;
				child.contextLifecycleSignal.removeFromMap(LifecycleSignal.POST_DESTROY, onChildDestroy);
			}
			else
			{
				_logger.warn("子context {0} 必须是 {1} 的子context", [child, this]);
			}
			return this;
		}
		
		public function addConfigHandler(matcher:IMatcher, handler:Function):IContext 
		{
			_configManager.addConfigHandler(matcher, handler);
			return this;
		}
		
		public function getLogger(source:Object):ILogger 
		{
			return _logManager.getLogger(source);
		}
		
		public function addLogTarget(target:ILogTarget):IContext 
		{
			_logManager.addLogTarget(target);
			return this;
		}
		
		public function detain(...instances):IContext 
		{
			const len:int = instances.length;
			for (var i:int = 0; i < len; i++) 
			{
				_pin.detain(instances[i]);
			}
			return this;
		}
		
		public function release(...instances):IContext 
		{
			const len:int = instances.length;
			for (var i:int = 0; i < len; i++) 
			{
				_pin.release(instances[i]);
			}
			return this;
		}
		
		public function get state():String 
		{
			return _lifecycle.state;
		}
		
		public function get uninitialized():Boolean 
		{
			return _lifecycle.uninitialized;
		}
		
		public function get initialized():Boolean 
		{
			return _lifecycle.initialized;
		}
		
		public function get active():Boolean 
		{
			return _lifecycle.active;
		}
		
		public function get suspended():Boolean 
		{
			return _lifecycle.suspended;
		}
		
		public function get destroyed():Boolean 
		{
			return _lifecycle.destroyed;
		}
		
		public function initialize(callback:Function = null):void 
		{
			_lifecycle.initialize(callback);
		}
		
		public function suspend(callback:Function = null):void 
		{
			_lifecycle.suspend(callback);
		}
		
		public function resume(callback:Function = null):void 
		{
			_lifecycle.resume(callback);
		}
		
		public function destroy(callback:Function = null):void 
		{
			_lifecycle.destroy(callback);
		}
		
		public function beforeInitializing(handler:Function):IContext 
		{
			_lifecycle.beforeInitializing(handler);
			return this;
		}
		
		public function whenInitializing(handler:Function):IContext 
		{
			_lifecycle.whenInitializing(handler);
			return this;
		}
		
		public function afterInitializing(handler:Function):IContext 
		{
			_lifecycle.afterInitializing(handler);
			return this;
		}
		
		public function beforeSuspending(handler:Function):IContext 
		{
			_lifecycle.beforeSuspending(handler);
			return this;
		}
		
		public function whenSuspending(handler:Function):IContext 
		{
			_lifecycle.whenSuspending(handler);
			return this;
		}
		
		public function afterSuspending(handler:Function):IContext 
		{
			_lifecycle.afterSuspending(handler);
			return this;
		}
		
		public function beforeResuming(handler:Function):IContext 
		{
			_lifecycle.beforeResuming(handler);
			return this;
		}
		
		public function whenResuming(handler:Function):IContext 
		{
			_lifecycle.whenResuming(handler);
			return this;
		}
		
		public function afterResuming(handler:Function):IContext 
		{
			_lifecycle.afterResuming(handler);
			return this;
		}
		
		public function beforeDestroying(handler:Function):IContext 
		{
			_lifecycle.beforeDestroying(handler);
			return this;
		}
		
		public function whenDestroying(handler:Function):IContext 
		{
			_lifecycle.whenDestroying(handler);
			return this;
		}
		
		public function afterDestroying(handler:Function):IContext 
		{
			_lifecycle.afterDestroying(handler);
			return this;
		}
		
		public function get contextLifecycleSignal():IContextLifecycleSignal
		{
			return _contextLifecycleSignal;
		}
		
	}

}